﻿using System;
using System.Collections.Generic;
using System.Text;
using System.ServiceModel;
using System.ComponentModel;
using System.Runtime.Serialization;

namespace ServerNodeLib
{
	/// <summary>
	/// Defines the state of a client node for reporting to the server.
	/// </summary>
	[DataContract()]
	public class NodeStatus
	{
		/// <summary>
		/// The current state of the node.
		/// </summary>
		[DataMember()]
		[DefaultValue(NodeState.Idle)]
		public NodeState State;
		/// <summary>
		/// A human-readable description of the node's status.  Usually lists the job or idle.
		/// </summary>
		[DataMember()]
		[DefaultValue("")]
		public String StatusDescription;
		/// <summary>
		/// A percent complete [0,100] of the current task.  Negative for idle.
		/// </summary>
		[DataMember()]
		[DefaultValue(-1)]
		public double PercentComplete;
		/// <summary>
		/// The time the current job started running.  Returns DateTime.Now when idle.
		/// </summary>
		[DataMember()]
		public DateTime StartTime;
		/// <summary>
		/// The time the current job stopped running.  Returns DateTime.Max when running.
		/// </summary>
		[DataMember()]
		public DateTime EndTime;
		/// <summary>
		/// The node's self-reported IpAddress
		/// Nodes behind NATs are not accessible, so there isn't a need
		/// to verify a node's IpAddress.
		/// 
		/// This is still around because in the earlier version of the code,
		/// the server connected directly with clients using this IpAddress.
		/// 
		/// Now with the pull-model, there is no longer a need.  However, I
		/// didn't delete the field since it may be useful to know IpAddress.
		/// </summary>
		[DataMember()]
		[DefaultValue("")]
		public String IpAddress;
		/// <summary>
		/// The name of the node
		/// </summary>
		[DataMember()]
		[DefaultValue("")]
		public String NodeName;
		/// <summary>
		/// The unique identifier of the node
		/// </summary>
		[DataMember()]
		public Guid NodeId;
		/// <summary>
		/// The guid of the currently active batch on the node
		/// </summary>
		[DataMember()]
		public Guid BatchId;
		/// <summary>
		/// Whether this node accepts new jobs
		/// </summary>
		[DataMember()]
		public bool AcceptNewJobs;
		/// <summary>
		/// How many seconds to wait when there is an error with updates
		/// </summary>
		[DataMember()]
		public int ErrorTimeout;
		/// <summary>
		/// How many seconds to wait before sending a new status update
		/// </summary>
		[DataMember()]
		public int NormalTimeout;
		/// <summary>
		/// The actual queue of results this node is waiting to send.
		/// </summary>
		[DataMember()]
		public List<Guid> ResultQueue;

		public override string ToString()
		{
			String stateStr = State.ToString();
			if (State != NodeState.Idle)
				stateStr += " " + StatusDescription;
			return string.Format(ServerNodeSettings.Default.NodeStringFormat,
				NodeName,
				stateStr,
				(AcceptNewJobs ? "On" : "Off")
				);
		}
	}

	/// <summary>
	/// The state of the node
	/// </summary>
	[DataContract()]
	public enum NodeState
	{
		/// <summary>
		/// An error has occurred and the node cannot take new batches
		/// </summary>
		[EnumMember()]
		Error = -1,
		/// <summary>
		/// Waiting for a batch job to execute
		/// </summary>
		[EnumMember()]
		Idle = 0,
		/// <summary>
		/// Currently executing a batch job
		/// </summary>
		[EnumMember()]
		Running = 1,
		/// <summary>
		/// Period between announcement and status message
		/// </summary>
		[EnumMember()]
		Announced = 5,
		/// <summary>
		/// Currently downloading resources from the server to execute batch
		/// </summary>
		[EnumMember()]
		DownloadingResources = 10,
		/// <summary>
		/// Currently sending resources and results to the server after finising a batch
		/// </summary>
		[EnumMember()]
		PostingResult = 11,
	}
}
